perm filename EFRPKT.C[11,HE] blob
sn#688196 filedate 1982-12-06 generic text, type T, neo UTF8
/* LINTLIBRARY */
/*
* efrecpckt..c
*
* EFTP Package
*
* THIS ASSUMES NOTHING ABOUT BYTE ORDER.
* EfRecPckt -- receive the next packet of an Eftp transfer
* EfAbort -- send an EFTP Abort packet
*
* Jeffrey Mogul @ Stanford 11-February-1981
*/
#define min(a,b) ( (a<b)? a : b )
#include <pupconstants.h>
#include <pupstatus.h>
#include <eftp.h>
EfRecPckt(Efchan, buf, blen)
struct EftpChan *Efchan; /* open eftp channel */
char *buf; /* data buffer */
int *blen; /* number of bytes we got */
{ /* */
int retry;
int rstat;
uchar rpuptype;
ulong rpupid;
char msgbuf[100];
int msgbuflen;
int dallying = 0; /* true iff we are waiting for second EFTPEND */
struct Port Sender;
while (1) { /* all exits from this loop are "return"s */
rstat = pupread(&Efchan->pchan, buf, blen, &rpuptype,
&rpupid, NULL, &Sender);
if (rstat == BADCKSUM) continue; /* try again */
if (rstat == TIMEOUT) return(TIMEOUT);
/* got a packet */
/* we now decide if the packet is one we want. If
* we are past sequence #0, it must be from out partner.
* Otherwise, if we are waiting to start with a specific
* host, it must be from that host. If it is packet #0
* from a host we want, remember the host address.
*/
if (Efchan->sequence) { /* we are already running */
if (!PortEQ(&Efchan->remport,&Sender)) {
/* somebody trying to horn in */
EfRecBusy(Efchan, &Sender);
continue;
}
}
else /* not yet started */
if ( (Efchan->remport.host) && (Efchan->remport.net) &&
(Efchan->remport.host != Sender.host ||
Efchan->remport.net != Sender.net) ) {
/* not the sender we were awaiting */
EfRecBusy(Efchan, &Sender);
continue;
}
else
{ /* remember this sender for future ref. */
Efchan->remport.host = Sender.host;
Efchan->remport.net = Sender.net;
Efchan->remport.socket = Sender.socket;
pupsetdest(&Efchan->pchan, &Efchan->remport);
}
/* packet is from our partner */
switch ((int)rpuptype) {
case EFTPDATA: /* data packet */
if (rpupid == Efchan->sequence) { /* sequence ok */
EfAck(Efchan, rpupid);
Efchan->sequence++;
return(OK);
}
if (rpupid == Efchan->sequence - 1) {
/* re-ack last packet */
EfAck(Efchan, rpupid);
break; /* keep trying */
}
if (rpupid == 0) { /* implicit restart */
EfAck(Efchan, rpupid);
Efchan->sequence = 1; /* restart sequence */
return(EFTP_RESTART);
}
/* POSSIBLE BUG: if we get two copies of packet #0,
* is it a missed ack or a restart? Treat it as a missed
* ack!
*/
/* sender is out of synch */
EfOutOfSynch(Efchan);
return(EFTP_OUTOFSYNCH);
case EFTPEND: /* end of transfer */
if (rpupid == Efchan->sequence) { /* sequence ok */
if (dallying) { /* we already saw one */
return(EFTP_ENDOFFILE);
}
else { /* first EFTPEnd */
EfAck(Efchan, rpupid);
dallying++; /* start dally */
pupsettimeout(&Efchan->pchan,
ONESEC*EFTP_DALLYWAIT); /* alter timeout */
Efchan->sequence++; /* bump seqeunce */
}
}
else { /* sender out of synch */
EfOutOfSynch(Efchan);
return(EFTP_OUTOFSYNCH);
}
break; /* gets here after first EFTPEnd */
case EFTPABORT:
EftpAbortCode = *(ushort *)msgbuf;
movestring(&msgbuf[2],EftpErrMsg,msgbuflen-2);
EftpErrMsg[msgbuflen-2] = 0; /* nullterm string */
return(EFTP_ABORT);
default: /* we got the wrong packet type! */
return(EFTP_ERROR);
}
}
/* should never get here */
}
/*
* EfAbort - send EFTP abort on a Pup channel
*/
EfAbort(pc, abcode, abmsg) /* send an EFTP abort packet */
struct PupChan *pc; /* pup channel for writing */
ushort abcode; /* abort code */
char *abmsg; /* abort message */
{ /* */
char abbuf[EFTP_MAX_PACKET]; /* for building abort message */
int msglen;
msglen = strlen(abmsg);
* ( (ushort *)&abbuf[0]) = abcode; /* put code into buffer */
movestring(abmsg, &abbuf[2], msglen);
/* copy human-readable message */
#ifdef PUP__NNSO /* nonstandard byte order */
if ( (pupgetmode(pc)&PCM_WFIXLAST) && (msglen&1)) {
/* oops! pupwrite will swap the last byte in the buffer! */
abbuf[2+msglen++] = ' '; /* lengthen the buffer, makes it
* even, then incr. msglen */
}
#endif /* */
pupwrite(pc,EFTPABORT,0,abbuf,msglen+2); /* send abort */
/* !!! SHOULD WE RETURN PROPER PUPID? !!! */
}
EfRecBusy(efc,sndr) /* send a Receiver Busy Abort */
struct EftpChan *efc; /* Eftp channel to our partner, NOT to sender */
struct Port *sndr; /* sender trying to horn in */
{ /* */
/* Since the intended recipient of the abort is not the destination
* on our Pup channel, we must temporarily alter the PupChan
* to reflect this.
*/
pupsetdest(&efc->pchan, sndr);
EfAbort(&efc->pchan, EFTPA_RECBUSY,
"Receiver busy -- another transfer in progress");
/* now, restore old PupChan destination */
pupsetdest(&efc->pchan, &efc->remport);
}
EfOutOfSynch(efc) /* send an Out of Synch Abort */
struct EftpChan *efc; /* Eftp channel to our partner */
{ /* */
EfAbort(&efc->pchan, EFTPA_OUTOFSYNCH,
"Packet received out of synch, transfer aborted");
}
EfAck(efc,seqnum) /* Acknowledge an EFTPDATA or EFTPEND */
struct EftpChan *efc; /* Eftp channel to our partner */
long seqnum; /* sequence number for Ack */
{ /* */
pupwrite(&(efc->pchan),EFTPACK,seqnum, NULL, 0);
}